#pragma once

////////////////
// const_node //
////////////////

inline const_node::const_node(implementation * i, handle h) 
	: _impl(i), _handle(h) { }

inline const_node::const_node()
	: _impl(0), _handle(0) { }

inline std::stringstream & const_node::stream()
	{ return _stream; }

inline const std::stringstream & const_node::stream() const
	{ return _stream; }

class const_node::const_attribute {
private:
	const const_node &	_node;
	const string &		_name;
public:
	const_attribute(const const_node & n, const string & name) 
		: _node(n), _name(name) { }
	const_attribute(const const_attribute & a) 
		: _node(a._node), _name(a._name) { }
public:
	template <class T> operator T ()
		{ return _node.attr<T>(_name); }
	template <class T> T def (const T & d = T())
		{ return _node.attr<T>(_name, def_t<T>(d)); }
};

template <class T> 
inline T const_node::attr(const string & name) const
{
	string val;
	if (null() || !get_attr(name, val))
		throw attribute_not_found();
	_stream.clear();
	_stream.str(val);
	T t;
	_stream >> t;
	if (_stream.fail())
		throw attribute_parse_error();
	return t;
}

template <> 
inline string const_node::attr(const string & name) const
{
	string val;
	if (null() || !get_attr(name, val))
		throw attribute_not_found();
	return val;
}

template <class T> 
inline bool const_node::query_attr(const string & name, T & value) const
{
	try {
		value = attr<T>(name);
		return true;
	} 
	catch (exception const &) {
		return false;
	}
}

template <class T> 
inline T const_node::attr(const string & name, def_t<T> d) const
{
	string val;
	if (null() || !get_attr(name, val))
		return d.val;
	_stream.clear();
	_stream.str(val);
	T t;
	_stream >> t;
	if (_stream.fail())
		return d.val;
	return t;
}

template <> 
inline string const_node::attr(const string & name, def_t<string> d) const
{
	string val;
	if (null() || !get_attr(name, val))
		return d.val;
	return val;
}

inline const_node::const_attribute const_node::operator [] (const string & name) const
	{ return const_attribute(* this, name); }

//////////
// node //
//////////

inline node::node(implementation * i, handle h)
	: const_node(i, h) { }

inline node::node()
	: const_node() { }

inline node::node(const const_node & n)
	: const_node(n) { }

class node::attribute {
private:
	node const &	_node;
	const string &	_name;
public:
	attribute(node const & n, const string & name) 
		: _node(n), _name(name) { }
	attribute(const attribute & a)
		: _node(a._node), _name(a._name) { }
public:
	template <class T> attribute & operator = (const T & value)
		{ _node.attr(_name, value); return * this; }
	template <class T> operator T ()
		{ return _node.attr<T>(_name); }
	template <class T> T def (const T & d = T())
		{ return _node.attr<T>(_name, def_t<T>(d)); }
};

template <class T> 
inline T node::attr(const string & name) const
	{ return const_node::attr<T>(name); }

template <class T> 
inline T node::attr(const string & name, def_t<T> d) const
	{ return const_node::attr<T>(name, d); }

template <class T> 
inline void node::attr(const string & name, const T & value) const
{
	if (null())
		throw attribute_not_found(); ///really it means that this node is not found
	_stream.str(string());
	_stream << value;
	set_attr(name, _stream.str());
}

template <> 
inline void node::attr(const string & name, const string & value) const
{ 
	if (null())
		throw attribute_not_found();
	set_attr(name, value); 
}

inline node::attribute node::operator [] (const string & name) const
	{ return attribute(* this, name); }

inline void node::children(const_node_list & nodes, filter f) const
	{ const_node::children(nodes, f); }

inline void node::children(const_node_vector & nodes, filter f) const
	{ const_node::children(nodes, f); }
